using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows;

namespace FileManager.Services
{
    public class DatFileDecryptor
    {
        /// <summary>
        /// 解密微信 .dat 文件
        /// </summary>
        /// <param name="filePath">dat文件路径</param>
        /// <returns>解密后的字节数组</returns>
        /// <exception cref="FileNotFoundException">文件不存在时抛出</exception>
        /// <exception cref="ArgumentException">不是.dat文件时抛出</exception>
        public async Task<byte[]> DecryptDatFileAsync(string filePath)
        {
            if (!File.Exists(filePath))
                throw new FileNotFoundException("文件不存在", filePath);

            if (Path.GetExtension(filePath).ToLowerInvariant() != ".dat")
                throw new ArgumentException("不是 .dat 文件", nameof(filePath));

            try
            {
                byte[] fileBytes = await File.ReadAllBytesAsync(filePath);
                return DecryptBytes(fileBytes);
            }
            catch (Exception ex)
            {
                throw new Exception("解密文件失败", ex);
            }
        }

        /// <summary>
        /// 解密.dat文件并保存为图片
        /// </summary>
        /// <param name="datFilePath">dat文件路径</param>
        /// <param name="outputPath">输出图片路径</param>
        /// <returns>保存后的图片路径</returns>
        public async Task<string> DecryptAndSaveAsImageAsync(string datFilePath, string outputPath = null)
        {
            try
            {
                byte[] decryptedBytes = await DecryptDatFileAsync(datFilePath);

                // 如果未指定输出路径，则在原文件旁创建文件
                if (string.IsNullOrEmpty(outputPath))
                {
                    string extension = DetectImageFormat(decryptedBytes);
                    outputPath = Path.Combine(
                        Path.GetDirectoryName(datFilePath),
                        Path.GetFileNameWithoutExtension(datFilePath) + extension);
                }

                // 确保输出目录存在
                Directory.CreateDirectory(Path.GetDirectoryName(outputPath));

                // 保存为图片文件
                await File.WriteAllBytesAsync(outputPath, decryptedBytes);

                return outputPath;
            }
            catch (Exception ex)
            {
                throw new Exception("解密并保存图片失败", ex);
            }
        }

        /// <summary>
        /// 解密.dat文件为BitmapImage对象（使用WPF的图像处理类，避免System.Drawing依赖）
        /// </summary>
        /// <param name="datFilePath">dat文件路径</param>
        /// <returns>BitmapImage对象</returns>
        public async Task<BitmapImage> DecryptToBitmapImageAsync(string datFilePath)
        {
            try
            {
                byte[] decryptedBytes = await DecryptDatFileAsync(datFilePath);

                using (var ms = new MemoryStream(decryptedBytes))
                {
                    var bitmapImage = new BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.StreamSource = ms;
                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                    bitmapImage.EndInit();
                    bitmapImage.Freeze(); // 冻结对象以在UI线程外使用
                    return bitmapImage;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("解密为BitmapImage失败", ex);
            }
        }

        /// <summary>
        /// 使用用户验证过的算法解密字节数组
        /// </summary>
        /// <param name="encryptedBytes">加密的字节数组</param>
        /// <returns>解密后的字节数组</returns>
        private byte[] DecryptBytes(byte[] encryptedBytes)
        {
            byte[] decryptedBytes = new byte[encryptedBytes.Length];
            
            // 空文件处理
            if (encryptedBytes.Length == 0)
                return decryptedBytes;
            
            // 获取密钥
            byte key;
            
            // 尝试JPEG格式验证 (FF D8)
            key = (byte)(encryptedBytes[0] ^ 0xFF);
            if (encryptedBytes.Length > 1 && (encryptedBytes[1] ^ key) == 0xD8)
            {
                // JPEG格式
                for (int i = 0; i < encryptedBytes.Length; i++)
                {
                    decryptedBytes[i] = (byte)(encryptedBytes[i] ^ key);
                }
            }
            else
            {
                // 尝试PNG格式验证 (89 50 4E 47)
                key = (byte)(encryptedBytes[0] ^ 0x89);
                for (int i = 0; i < encryptedBytes.Length; i++)
                {
                    decryptedBytes[i] = (byte)(encryptedBytes[i] ^ key);
                }
            }
            
            return decryptedBytes;
        }

        /// <summary>
        /// 尝试检测图片格式并返回适当的扩展名
        /// </summary>
        /// <param name="imageBytes">图片字节数组</param>
        /// <returns>图片扩展名</returns>
        public string DetectImageFormat(byte[] imageBytes)
        {
            if (imageBytes == null || imageBytes.Length < 8)
                return ".jpg"; // 默认返回 jpg

            // 检查文件头
            if (imageBytes[0] == 0xFF && imageBytes[1] == 0xD8) // JPEG
                return ".jpg";
            else if (imageBytes[0] == 0x89 && imageBytes[1] == 0x50 && imageBytes[2] == 0x4E && imageBytes[3] == 0x47) // PNG
                return ".png";
            else if (imageBytes[0] == 0x47 && imageBytes[1] == 0x49 && imageBytes[2] == 0x46) // GIF
                return ".gif";
            else if (imageBytes[0] == 0x42 && imageBytes[1] == 0x4D) // BMP
                return ".bmp";
            else
                return ".jpg"; // 默认返回 jpg
        }
    }
}